package com.zhongwang.mms.module.material.service;

import com.zhongwang.mms.gen.entity.*;
import com.zhongwang.mms.module.basic.dao.MMaterialsDao;
import com.zhongwang.mms.module.material.dao.MInventoryDao;
import com.zhongwang.mms.module.material.dao.MInventoryProjectMarkDao;
import com.zhongwang.mms.module.material.dao.MMarkRelationDao;
import com.zhongwang.mms.module.material.dao.MProjectInventoryMarkDao;
import com.zhongwang.mms.module.material.model.MProjectInventoryMarkModel;
import com.zhongwang.mms.module.system.log.LogService;
import com.zhongwang.mms.util.BigDecimalUtils;
import com.zhongwang.mms.util.FileUtils;
import com.zhongwang.mms.util.ShiroUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;


/**
 * @Description: 项目划库存 服务层
 * @Author: China.wsg
 * @Date: 2020/04/23 19:43
 */
@Service
public class MProToItyService {

    @Autowired
    private MInventoryDao inventoryDao;
    @Autowired
    private MProjectInventoryMarkDao projectInventoryMarkDao;
    @Autowired
    private MMaterialsDao materialsDao;
    @Autowired
    private LogService logService;
    @Autowired
    private MInventoryService inventoryService;
    @Autowired
    private MMarkRelationDao markRelationDao;
    @Autowired
    private MInventoryProjectMarkDao inventoryProjectMarkDao;

    @Value("${user.upload.path}")
    private String uploadPath;

    /**
     * 保存项目划库存标记
     *
     * @param projectInventoryMark 保存信息
     * @return json 数据
     */
    @Transactional
    public String save(MProjectInventoryMark projectInventoryMark) {

        // 判断库存是否充足
        MInventory inventory = inventoryDao.selectByPrimaryKey(projectInventoryMark.getPimBeforeItyId());
        double a = inventory.getItyAvaNum();
        double b = inventory.getItyAvaWeight();
        double c = projectInventoryMark.getPimNum();
        double d = projectInventoryMark.getPimWeight();
        if (a < c || b < d) {
            return "标记量大于可用量";
        }

        // 保存标记记录
        projectInventoryMark.setPimDate(new Date());
        projectInventoryMark.setPimProposer(ShiroUtils.getUser().getName());
        projectInventoryMark.setPimAppStatus(1); //标记状态：0=删除 1=未提交 2=已提交 3=执行
        projectInventoryMark.setPimAccount(ShiroUtils.getLoginName());
        projectInventoryMark.setPimPrice(inventory.getItyPrice());
        projectInventoryMark.setPimMatId(inventory.getItyMatId());
        projectInventoryMarkDao.insert(projectInventoryMark);

        // 更新库存表可用数量及重量
        inventory.setItyAvaNum(BigDecimalUtils.sub(inventory.getItyAvaNum(), projectInventoryMark.getPimNum()));
        inventory.setItyAvaWeight(BigDecimalUtils.sub(inventory.getItyAvaWeight(), projectInventoryMark.getPimWeight()));
        inventoryDao.updateByPrimaryKeySelective(inventory);

        MMaterials materials = materialsDao.selectByPrimaryKey(inventory.getItyMatId());
        logService.saveLog("项目划库存标记", materials.getMatNameDesc() + "<br>标记项目：" + inventory.getItyProCode()
                + "  " + inventory.getItyProName()
                + "<br>标记量：" + projectInventoryMark.getPimWeight() + "  " + materials.getMatWeightUnit());

        return "";
    }

    /**
     * 保存项目划库存标记（批量）
     *
     * @param arr 标记Id集合
     * @return
     */
    @Transactional
    public void togetherMark(List<Integer> arr) {

        MProjectInventoryMark projectInventoryMark;  // 标记信息
        MInventory inventory;

        // 循环标记
        for (int i = 0; i < arr.size(); i++) {

            inventory = inventoryDao.selectByPrimaryKey(arr.get(i));
            projectInventoryMark = new MProjectInventoryMark();
            projectInventoryMark.setPimBeforeItyId(inventory.getItyId());
            projectInventoryMark.setPimNum(inventory.getItyAvaNum());
            projectInventoryMark.setPimWeight(inventory.getItyAvaWeight());
            projectInventoryMark.setPimDate(new Date());
            projectInventoryMark.setPimProposer(ShiroUtils.getUser().getName());
            projectInventoryMark.setPimAppStatus(1); //标记状态：0=删除 1=未提交 2=已提交 3=执行
            projectInventoryMark.setPimAccount(ShiroUtils.getLoginName());
            projectInventoryMark.setPimPrice(inventory.getItyPrice());
            projectInventoryMark.setPimMatId(inventory.getItyMatId());
            projectInventoryMarkDao.insert(projectInventoryMark);

            // 更新库存表可用数量及重量
            inventory.setItyAvaNum(BigDecimalUtils.sub(inventory.getItyAvaNum(), projectInventoryMark.getPimNum()));
            inventory.setItyAvaWeight(BigDecimalUtils.sub(inventory.getItyAvaWeight(), projectInventoryMark.getPimWeight()));
            inventoryDao.updateByPrimaryKeySelective(inventory);
        }
        logService.saveLog("项目划库存批量标记", "批量标记数量：" + arr.size() + " 条");
    }


    /**
     * 修改项目划库存标记状态
     *
     * @param projectInventoryMark 修改信息
     * @return json 数据
     */
    @Transactional
    public int updateStatus(MProjectInventoryMark projectInventoryMark) {

        // 标记记录
        MProjectInventoryMark proToItyMark = projectInventoryMarkDao.selectByPrimaryKey(projectInventoryMark.getPimId());
        MInventory inventory = inventoryDao.selectByPrimaryKey(proToItyMark.getPimBeforeItyId());
        MMaterials materials = materialsDao.selectByPrimaryKey(inventory.getItyMatId());

        logService.saveLog(projectInventoryMark.getPimAppStatus() == 0 ? "删除项目划库存标记" : "提交项目划库存标记",
                "标记项目：" + inventory.getItyProCode() + "  " + inventory.getItyProName() +
                        "<br> 标记物料：" + materials.getMatNameDesc() + "<br> 标记重量：" + proToItyMark.getPimWeight());

        if (projectInventoryMark.getPimAppStatus() == 0) {
            // 标记删除：将原料在库可用数量、可用重量增加标记量
            inventory.setItyAvaNum(BigDecimalUtils.add(inventory.getItyAvaNum(), proToItyMark.getPimNum()));
            inventory.setItyAvaWeight(BigDecimalUtils.add(inventory.getItyAvaWeight(), proToItyMark.getPimWeight()));
            inventoryDao.updateByPrimaryKey(inventory);
        }
        int row = projectInventoryMarkDao.updateByPrimaryKeySelective(projectInventoryMark);
        return row;
    }

    /**
     * 修改项目划库存标记
     *
     * @param projectInventoryMark 保存信息
     * @return json 数据
     */
    @Transactional
    public String edit(MProjectInventoryMark projectInventoryMark) {

        // 判断库存是否充足
        MProjectInventoryMark oldMark = projectInventoryMarkDao.selectByPrimaryKey(projectInventoryMark.getPimId());
        MInventory inventory = inventoryDao.selectByPrimaryKey(oldMark.getPimBeforeItyId());
        double a = BigDecimalUtils.add(inventory.getItyAvaNum(), oldMark.getPimNum());
        double b = BigDecimalUtils.add(inventory.getItyAvaWeight(), oldMark.getPimWeight());
        double c = projectInventoryMark.getPimNum();
        double d = projectInventoryMark.getPimWeight();
        if (a < c || b < d) {
            return "标记量大于可用量";
        }

        // 修改标记记录
        projectInventoryMarkDao.updateByPrimaryKeySelective(projectInventoryMark);

        // 更新库存表可用数量及重量
        inventory.setItyAvaNum(BigDecimalUtils.sub(a, projectInventoryMark.getPimNum()));
        inventory.setItyAvaWeight(BigDecimalUtils.sub(b, projectInventoryMark.getPimWeight()));
        inventoryDao.updateByPrimaryKeySelective(inventory);

        logService.saveLog("项目划库存标记修改", oldMark, projectInventoryMark);

        return "";
    }

    /**
     * 批量提交库存划项目标记
     *
     * @param arr 标记Id集合
     * @return
     */
    @Transactional
    public void togetherCommit(List<Integer> arr) {

        MProjectInventoryMark projectInventoryMark;
        for (int i = 0; i < arr.size(); i++) {
            projectInventoryMark = new MProjectInventoryMark();
            projectInventoryMark.setPimId(arr.get(i));
            projectInventoryMark.setPimAppStatus(2);
            projectInventoryMarkDao.updateByPrimaryKeySelective(projectInventoryMark);
        }

        logService.saveLog("项目划库存批量提交", "批量提交" + arr.size() + "条");
    }

    /**
     * 项目划库存执行（单条）
     *
     * @param pimId
     * @return
     */
    @Transactional
    public String checkSingle(Integer pimId) {

        String msg = "";  // 返回提示信息
        String errorReason;

        MProjectInventoryMark proToIty = projectInventoryMarkDao.selectByPrimaryKey(pimId);
        MInventory inventory = inventoryDao.selectByPrimaryKey(proToIty.getPimBeforeItyId());
        MMaterials materials = materialsDao.selectByPrimaryKey(inventory.getItyMatId());

        // 校验是否满足项目划库存执行条件
        errorReason = checkValidate(proToIty, inventory);
        if (errorReason.length() == 0) {

            //满足条件 执行操作
            checkMethod(proToIty, inventory);
        } else {
            msg = msg + errorReason + " <br>项目划库存执行失败";
            return msg;
        }

        logService.saveLog("项目划库存执行", materials.getMatNameDesc() + "<br>标记项目：" + inventory.getItyProCode() + "  " + inventory.getItyProName()
                + "<br>标记量：" + proToIty.getPimWeight() + "  " + materials.getMatWeightUnit());
        return "项目划库存执行成功！";

    }

    /**
     * 项目划库存执行（批量）
     *
     * @param arr 明细Id集合
     * @return
     */
    @Transactional
    public String checkTogether(List<Integer> arr) {
        String msg = "";  // 返回提示信息
        String errorReason; // 校验原因
        int errorCount = 0; // 审核失败记录数
        int successCount = 0; // 成功审核记录数
        MProjectInventoryMark proToIty;
        MInventory inventory;

        for (int i = 0; i < arr.size(); i++) {
            proToIty = projectInventoryMarkDao.selectByPrimaryKey(arr.get(i));
            inventory = inventoryDao.selectByPrimaryKey(proToIty.getPimBeforeItyId());

            // 校验是否满足项目划库存执行条件
            errorReason = checkValidate(proToIty, inventory);
            if (errorReason.length() == 0) {

                //满足条件 执行操作
                checkMethod(proToIty, inventory);
                successCount++;
            } else {
                msg = msg + errorReason;
                errorCount++;
                continue;
            }
        }

        logService.saveLog("项目划库存批量执行", "执行成功：" + successCount + "条, 执行失败：" + errorCount + "条");
        return msg.length() > 0 ? msg + "<br> 以上数据项目划库存执行失败！" : "项目划库存执行成功！";
    }

    /**
     * 项目划库存撤销（单条）
     *
     * @param pimId
     * @return
     */
    @Transactional
    public String cancelSingle(Integer pimId) {

        String msg = "";  // 返回提示信息
        String errorReason;

        MProjectInventoryMark proToIty = projectInventoryMarkDao.selectByPrimaryKey(pimId);
        MInventory beforeInventory = inventoryDao.selectByPrimaryKey(proToIty.getPimBeforeItyId());
        MInventory afterInventory = inventoryDao.selectByPrimaryKey(proToIty.getPimAfterItyId());
        MMaterials materials = materialsDao.selectByPrimaryKey(beforeInventory.getItyMatId());

        // 校验是否满足项目划库存撤销条件
        errorReason = checkCancelValidate(proToIty, beforeInventory, afterInventory);
        if (errorReason.length() == 0) {

            //满足条件 执行操作
            cancelMethod(proToIty, beforeInventory, afterInventory);
        } else {
            msg = msg + errorReason + "<br>项目划库存撤销失败";
            return msg;
        }

        logService.saveLog("项目划库存撤销", materials.getMatNameDesc() + "<br>标记项目：" + beforeInventory.getItyProCode() + "  " + beforeInventory.getItyProName()
                + "<br>标记量：" + proToIty.getPimWeight() + "  " + materials.getMatWeightUnit());
        return "项目划库存撤销成功！";

    }

    /**
     * 校验是否满足项目划库存执行条件
     *
     * @param projectInventoryMark 项目划库存记录
     * @param inventory            原料在库
     * @return
     */
    private String checkValidate(MProjectInventoryMark projectInventoryMark, MInventory inventory) {

        String errorReason = "";
        // 如果已经被执行，不允许二次执行(pim_app_status 0删除 1未提交 2已提交 3执行 4废除)
        // 提示信息：项目号 项目名称 标记重量 失败原因
        if (projectInventoryMark.getPimAppStatus() == 3) {

            errorReason = errorReason + "<br>" + inventory.getItyProCode() + "  " + inventory.getItyProName() + "  标记量 " + projectInventoryMark.getPimWeight() + "  已经被执行";
        }

        // 判断库存在库量是否充足
        double a = inventory.getItyNum();
        double b = inventory.getItyWeight();
        double c = projectInventoryMark.getPimNum();
        double d = projectInventoryMark.getPimWeight();
        if (a < c || b < d) {
            errorReason = errorReason + "<br>" + inventory.getItyProCode() + "  " + inventory.getItyProName() + "  标记量 " + projectInventoryMark.getPimWeight() + "  库存在库量不足";
        }

        return errorReason;
    }

    /**
     * 项目划库存执行
     *
     * @param proToIty        标记记录
     * @param beforeInventory 原料在库
     */
    private void checkMethod(MProjectInventoryMark proToIty, MInventory beforeInventory) {

        // 封装库存在库实体并保存
        MInventory afterInventory = new MInventory();
        afterInventory.setItyMatId(beforeInventory.getItyMatId());
        afterInventory.setItyInType(1);// 库存在库
        afterInventory.setItyProName("项目剩余备件");
        afterInventory.setItyNum(proToIty.getPimNum());
        afterInventory.setItyWeight(proToIty.getPimWeight());
        afterInventory.setItyAvaNum(proToIty.getPimNum());
        afterInventory.setItyAvaWeight(proToIty.getPimWeight());
        afterInventory.setItyPrice(beforeInventory.getItyPrice());
        afterInventory.setItyStoId(beforeInventory.getItyStoId());
        afterInventory.setItyMatSapCode(beforeInventory.getItyMatSapCode());
        // 判断：如果原料在库 ‘特殊说明’ 字段不为空时，将项目更改为[项目剩余备件],其余字段内容不变，在库类型更改为[1:库存在库]
        if (("".equals(beforeInventory.getItySpec()) || beforeInventory.getItySpec() == null) &&
                ("".equals(proToIty.getPimRemark()) || proToIty.getPimRemark() == null)) {

            afterInventory.setItyProCode("");
            afterInventory.setItySpec("");
            afterInventory.setItyTrackCode("");
        } else {

            String afterSpec;
            if (!"".equals(proToIty.getPimRemark()) && proToIty.getPimRemark() != null) {
                afterSpec = beforeInventory.getItySpec() == null ? "" : beforeInventory.getItySpec() + "/" + proToIty.getPimRemark();
            } else {
                afterSpec = beforeInventory.getItySpec();
            }
            afterInventory.setItyProCode(beforeInventory.getItyProCode());
            afterInventory.setItySpec(afterSpec);
            afterInventory.setItyTrackCode(beforeInventory.getItyTrackCode());
        }
        afterInventory = inventoryService.addInventory(afterInventory, 1);

        // 更新项目划库存表信息
        proToIty.setPimAfterItyId(afterInventory.getItyId());
        proToIty.setPimAppStatus(3);
        proToIty.setPimChekcDate(new Date());
        proToIty.setPimExecutor(ShiroUtils.getUser().getName());
        projectInventoryMarkDao.updateByPrimaryKeySelective(proToIty);

        // 减少原项目在库量
        inventoryService.subInventory(beforeInventory, proToIty.getPimNum(), proToIty.getPimWeight(), 0.0, 0.0);

    }

    /**
     * 项目划库存撤销
     *
     * @param proToIty        项目划库存记录
     * @param beforeInventory 标记前原料在库
     * @param afterInventory  执行后对应原料在库
     */
    private void cancelMethod(MProjectInventoryMark proToIty, MInventory beforeInventory, MInventory afterInventory) {

        // 减少执行后对应原料在库
        inventoryService.subInventory(afterInventory, proToIty.getPimNum(), proToIty.getPimWeight(), proToIty.getPimNum(), proToIty.getPimWeight());

        // 更新项目划库存表信息
        proToIty.setPimAfterItyId(null);
        proToIty.setPimAppStatus(2);
        proToIty.setPimChekcDate(null);
        proToIty.setPimExecutor(null);
        projectInventoryMarkDao.updateByPrimaryKey(proToIty);

        // 增加标记前原料在库
        beforeInventory.setItyNum(BigDecimalUtils.add(beforeInventory.getItyNum(), proToIty.getPimNum()));
        beforeInventory.setItyWeight(BigDecimalUtils.add(beforeInventory.getItyWeight(), proToIty.getPimWeight()));
        inventoryDao.updateByPrimaryKeySelective(beforeInventory);
    }

    /**
     * 校验是否满足项目划库存撤销条件
     *
     * @param projectInventoryMark 项目划库存记录
     * @param beforeInventory      标记前原料在库
     * @param afterInventory       执行后对应原料在库
     * @return
     */
    private String checkCancelValidate(MProjectInventoryMark projectInventoryMark, MInventory beforeInventory, MInventory afterInventory) {

        String errorReason = "";
        // 如果已经被执行，不允许二次执行(pim_app_status 0删除 1未提交 2已提交 3执行 4废除)
        // 提示信息：项目号 项目名称 标记重量 失败原因
        if (projectInventoryMark.getPimAppStatus() != 3) {

            errorReason = errorReason + "<br>" + beforeInventory.getItyProCode() + "  " + beforeInventory.getItyProName() + "  标记量 " + projectInventoryMark.getPimWeight() + "  已经被撤销";
        }

        // 判断是否被库存划项目使用
        MMarkRelationExample ex = new MMarkRelationExample();
        MMarkRelationExample.Criteria criteria = ex.createCriteria();
        criteria.andMrtPimIdEqualTo(projectInventoryMark.getPimId());
        criteria.andMrtStatusEqualTo(1);
        List<MMarkRelation> markRelations = markRelationDao.selectByExample(ex);

        if (markRelations != null && markRelations.size() > 0) {

            MInventoryProjectMark inventoryProjectMark = inventoryProjectMarkDao.selectByPrimaryKey(markRelations.get(0).getMrtIpmId());
            errorReason = errorReason + "<br>项目划库存的物料已经被库存划项目<br>" + inventoryProjectMark.getIpmInProjectCode() + "  " + inventoryProjectMark.getIpmInProjectName() +
                    "  划" + inventoryProjectMark.getIpmWeight() + "kg<br>请先撤销以上库存划项目标记记录！";
            return errorReason;
        }

        // 判断库存在库量是否充足
        double a = afterInventory.getItyAvaNum();
        double b = afterInventory.getItyAvaWeight();
        double c = projectInventoryMark.getPimNum();
        double d = projectInventoryMark.getPimWeight();
        if (a < c || b < d) {
            errorReason = errorReason + "<br>" + beforeInventory.getItyProCode() + "  " + beforeInventory.getItyProName() + "  标记量 " + projectInventoryMark.getPimWeight() + "  已被使用";
        }

        return errorReason;
    }

    /**
     * 列表 导出
     *
     * @param projectInventoryMarkModel 查询条件
     * @return list
     */
    public void exportExcel(HttpServletResponse response, MProjectInventoryMarkModel projectInventoryMarkModel) {
        List<MProjectInventoryMarkModel> list = projectInventoryMarkDao.findMarkListByQuery(projectInventoryMarkModel);;
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        String path = uploadPath + user.getAccount() + "/";
        FileUtils.export(path,"项目划库存列表.xls", MProjectInventoryMarkModel.class, "sheet1", list, response);
    }


}
